/*
 * @Author: Mr.Gao hansong_gao2022@163.com
 * @Date: 2025-03-31 18:34:58
 * @LastEditors: Mr.Gao hansong_gao2022@163.com
 * @LastEditTime: 2025-04-01 18:33:39
 * @FilePath: /ThreadPool/ThreadPool.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#pragma once

#include <iostream>
#include <unistd.h>
#include <string>
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <functional>
#include <condition_variable>
#include <functional>

static const int gdefaultnum = 5;
 
using func_t = std::function<void(std::string)>;

void test()
{
    while(true)
    {
        std::cout << "hello world" << std::endl;
        sleep(1);
    }
}

template<class T>
class ThreadPool
{
private:
    ThreadPool(int thread_num = gdefaultnum)
        : _thread_num(thread_num),_isrunning(false)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }
    ThreadPool(const ThreadPool<T>&) = delete;
    ThreadPool<T>& operator=(const ThreadPool<T>&) = delete;
    bool IsEmpty()
    {
        return _task_queue.empty();
    }
    // 任务处理函数，每个线程执行此函数来处理任务
    void HandlerTask(const std::string& name)
    {
        while (true)
        {
            //取任务
            LockQueue();
            // 如果任务队列为空&&线程池不退出，就去指定的条件变量下去休眠
            while(IsEmpty() && _isrunning)   //使用while，防止伪唤醒
            {
                _sleep_thread_num++;
                Sleep();    //会把持有的锁释放掉
                _sleep_thread_num--;
            }
            //判定一种情况,任务队列为空&&线程池要退出了
            if(IsEmpty() && !_isrunning)
            {
                std::cout << name << " quit" << std::endl;
                UnLockQueue();
                break;
            }
            //有任务 || 被唤醒
            T t = _task_queue.front();
            _task_queue.pop();
            UnLockQueue();
                
            //处理任务
            t(); // 处理任务，此处不能/不用在临界区处理
            std::cout << name << ":" << t.result() << std::endl;
        }
    }
    void LockQueue()
    {
        pthread_mutex_lock(&_mutex);
    }
    void UnLockQueue()
    {
        pthread_mutex_unlock(&_mutex);
    }
    void WakeUp()
    {
        pthread_cond_signal(&_cond);
    }
    void WakeUpAll()
    {
        pthread_cond_broadcast(&_cond);
    }
    void Sleep()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }
    void InitAndStart()
    {
        _isrunning = true;
        for (int i = 0; i < _thread_num; i++)
        {  
            std::string name = "thread-" + std::to_string(i+1);
            _threads.emplace_back(std::bind(&ThreadPool::HandlerTask, this, std::placeholders::_1), name);
        }
    } 
public:
    static ThreadPool<T>* GetInstance()
    {
        if(_tp == nullptr)
        {
            std::lock_guard<std::mutex> lock(_sig_mutex);
            if(_tp == nullptr)
            {
                std::cout << "create threadpool\n";
                _tp = new ThreadPool<T>();
                _tp->InitAndStart();
            }
            else
            {
                std::cout << "get threadpool\n";
            }
        }
        return _tp;
    } 
    void Stop()
    {
        LockQueue();
        _isrunning = false; 
        WakeUpAll();
        UnLockQueue();  
    }

    void Equeue(const T& in)
    {
        LockQueue();
        //向线程池push任务时，需要先判断线程池是否在运行，在运行才可以push任务
        if(_isrunning)
        {
            _task_queue.push(in);
            if(_sleep_thread_num > 0)
                WakeUp();
        }
        UnLockQueue();
    }

    ~ThreadPool()
    {
        for (auto& thread : _threads)
        {
            if (thread.joinable())
                thread.join();
        }
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }
private:
    int _thread_num;
    std::vector<std::thread> _threads;
    std::queue<T> _task_queue;
    bool _isrunning;

    int _sleep_thread_num;   //休眠线程数

    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

    //单例模式
    static ThreadPool<T>* _tp;
    static std::mutex _sig_mutex;
};

template<class T>
ThreadPool<T>* ThreadPool<T>::_tp = nullptr;
template<class T>
std::mutex ThreadPool<T>::_sig_mutex;